#include "MainWidget.h"
#include "ui_MainWidget.h"

#include <QDebug>

#define CHANNEL_POINT_CNT 4096
#define INI_Cfg_Name "Settings.ini"
#define INI_Cfg_LastVar         "LastVar"
#define INI_Cfg_LastSerialPort  "SerialPort"
#define INI_Cfg_LastBaudrate    "Baudrate"
#define INI_Cfg_LastSlaveID     "SlaveID"

MainWidget::MainWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWidget)
{
    m_xbufValuesPtr=nullptr;
    m_ybufValuesPtr=nullptr;
    m_modbusobj=new ModbusHelp;

    m_isLoadingFiles=false;

    ui->setupUi(this);
    this->setWindowTitle(tr("WaveDataToHexFile"));
    ui->tabWidget->setCurrentIndex(0);
    ui->widget_wave_chX->setAutoFillBackground(true);
    ui->widget_wave_chY->setAutoFillBackground(true);
    ui->comboboxBaudrate->setCurrentIndex(2);

    //读取一些上次使用的值
    QSettings setting(INI_Cfg_Name,QSettings::IniFormat);
    setting.beginGroup(INI_Cfg_LastVar);
    ui->comboboSerialPort->setCurrentText(
                setting.value(INI_Cfg_LastSerialPort,"COM1").toString()
                );
    ui->comboboxBaudrate->setCurrentText(
                setting.value(INI_Cfg_LastBaudrate,"19200").toString()
                );
    ui->spinbox_SlaveID->setValue(
                setting.value(INI_Cfg_LastSlaveID,1).toInt()
                );
    setting.endGroup();

    connect(ui->btnLoadFiles,SIGNAL(clicked()),
            this,SLOT(on_loadDataFiles())
            );

    connect(ui->spinBox_XMax,SIGNAL(valueChanged(double)),
            this,SLOT(on_LimitValueChanged())
            );
    connect(ui->spinBox_XMin,SIGNAL(valueChanged(double)),
            this,SLOT(on_LimitValueChanged())
            );
    connect(ui->spinBox_YMax,SIGNAL(valueChanged(double)),
            this,SLOT(on_LimitValueChanged())
            );
    connect(ui->spinBox_YMin,SIGNAL(valueChanged(double)),
            this,SLOT(on_LimitValueChanged())
            );

    ui->widget_wave_chX->installEventFilter(this);
    ui->widget_wave_chY->installEventFilter(this);

}

MainWidget::~MainWidget()
{
    if(m_xbufValuesPtr){
        delete m_xbufValuesPtr;
        m_xbufValuesPtr=nullptr;
    }
    if(m_ybufValuesPtr){
        delete m_ybufValuesPtr;
        m_ybufValuesPtr=nullptr;
    }
    delete ui;
}

///
/// \\brief on_loadDataFiles
///加载数据文件
void MainWidget::on_loadDataFiles()
{
    //获取要加载的文件名
    QStringList filenames;
    if(ui->comboBox_LoadFileMode->currentIndex()!=2){
        QString str;
        str=QFileDialog::getOpenFileName(Q_NULLPTR,
                                         tr("Select File"),
                                         nullptr,
                                         tr("CSV File (*.csv);;All File (*.*)")
                                         );


        if(!str.isNull() && !str.isEmpty()){
            QFileInfo info(str);
            if(info.exists()){
                filenames<<str;
            }
        }
    }else{
        QStringList l;
        l=QFileDialog::getOpenFileNames(
                    Q_NULLPTR,
                    tr("Select Files"),
                    nullptr,
                    tr("CSV Files (*.csv);;All Files (*.*)")
                    );
        if(l.count()>=2){
            QFileInfo info0(l[0]);
            QFileInfo info1(l[0]);
            if(info0.exists() && info1.exists()){
                QMessageBox msgBox;
                msgBox.setText(tr("Is File '%1' include Channel X data?").arg(l[0]));
                msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
                msgBox.setDefaultButton(QMessageBox::Yes);
                int ret = msgBox.exec();
                if(ret==QMessageBox::Yes){
                    filenames<<l[0];
                    filenames<<l[1];
                }else{
                    filenames<<l[1];
                    filenames<<l[0];
                }
            }
        }else if(l.count()==1){
            QMessageBox msgBox;
            msgBox.setText(tr("Please Select Two Files!"));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.exec();
        }
    }

    if(filenames.isEmpty()) return;
//    qDebug()<<filenames;

    //加载数据到成员变量
    QVector<double> xvalues,yvalues;
    QRegularExpression re;
    QRegularExpressionMatch match;
    QFile file;
    re.setPattern("[+|-]?\\d+\\.?\\d*(?:E\\+{1}\\d+|E\\-{1}\\d+|E{1}\\d+)?");
    re.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
    if(ui->comboBox_LoadFileMode->currentIndex()==0){       //单文件 X,Y 两列模式
        file.setFileName(filenames[0]);
        if(!file.open(QIODevice::ReadOnly)){
            QMessageBox msgBox;
            msgBox.setText(tr("Open File '%1' Failed!").arg(filenames[0]));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.exec();
            return;
        }

        QTextStream stream(&file);
        int index = 0;
        bool isdouble=false;
        double dt;
        do{
            if(stream.atEnd()){
                break;
            }

            QString line = stream.readLine();
            index=0;
            match = re.match(line, index);
            if(match.hasMatch()){
                QString digits=match.captured(0);
                dt=digits.toDouble(&isdouble);
                if(isdouble){
                    xvalues.append(dt);
                }

                index=match.capturedEnd();
                match = re.match(line, index);
                if(match.hasMatch()){
                    digits=match.captured(0);
                    dt=digits.toDouble(&isdouble);
                    if(isdouble){
                        yvalues.append(dt);
                    }
                }
            }

        }while(1);

        file.close();

    }else if(ui->comboBox_LoadFileMode->currentIndex()==1){     //单文件 X,Y 单列连续模式
        file.setFileName(filenames[0]);
        if(!file.open(QIODevice::ReadOnly)){
            QMessageBox msgBox;
            msgBox.setText(tr("Open File '%1' Failed!").arg(filenames[0]));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.exec();
            return;
        }

        QTextStream stream(&file);
        int index=0;
        bool isdouble=false;
        double dt;
        do{
            if(stream.atEnd()){
                break;
            }
            QString line = stream.readLine();
            index=0;
            do{
                match = re.match(line, index);
                if(match.hasMatch()){
                    QString digits=match.captured(0);
                    dt=digits.toDouble(&isdouble);
                    if(isdouble){
                        xvalues.append(dt);
                    }
                    index=match.capturedEnd();
                }else{
                    break;
                }
            }while(1);
        }while(1);
        file.close();

        int channelcnt=xvalues.count();
        if(channelcnt<=0) return;
        if(channelcnt%2){
            QMessageBox msgBox;
            msgBox.setText(tr("Number of Data In File '%1' is not even!").arg(filenames[0]));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.exec();
            return;
        }

        channelcnt=channelcnt/2;
        for (int i = 0; i < channelcnt; ++i) {
            yvalues.append(xvalues[i+channelcnt]);
        }
        xvalues.remove(channelcnt,channelcnt);

    }else if(ui->comboBox_LoadFileMode->currentIndex()==2){     //双文件 X,Y 各对应一个文件 模式
        if(filenames.count()<2){
            return;
        }

        file.setFileName(filenames[0]);
        if(!file.open(QIODevice::ReadOnly)){
            QMessageBox msgBox;
            msgBox.setText(tr("Open File '%1' Failed!").arg(filenames[0]));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.exec();
            return;
        }

        QFile file2;
        file2.setFileName(filenames[1]);
        if(!file2.open(QIODevice::ReadOnly)){
            file.close();
            QMessageBox msgBox;
            msgBox.setText(tr("Open File '%1' Failed!").arg(filenames[1]));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.exec();
            return;
        }

        QTextStream stream(&file);
        int index=0;
        bool isdouble=false;
        double dt;
        do{
            if(stream.atEnd()){
                break;
            }
            QString line = stream.readLine();
            index=0;
            do{
                match = re.match(line, index);
                if(match.hasMatch()){
                    QString digits=match.captured(0);
                    dt=digits.toDouble(&isdouble);
                    if(isdouble){
                        xvalues.append(dt);
                    }
                    index=match.capturedEnd();
                }else{
                    break;
                }
            }while(1);
        }while(1);
        file.close();

        stream.reset();
        stream.setDevice(&file2);
        index=0;
        do{
            if(stream.atEnd()){
                break;
            }
            QString line = stream.readLine();
            index=0;
            do{
                match = re.match(line, index);
                if(match.hasMatch()){
                    QString digits=match.captured(0);
                    dt=digits.toDouble(&isdouble);
                    if(isdouble){
                        yvalues.append(dt);
                    }
                    index=match.capturedEnd();
                }else{
                    break;
                }
            }while(1);
        }while(1);
        file2.close();

    }

    if(xvalues.count() != yvalues.count()){
        QMessageBox msgBox;
        msgBox.setText(tr("Number of Data In CHX and CHY is not equal!"));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
    }


    if(m_xbufValuesPtr){
        delete m_xbufValuesPtr;
        m_xbufValuesPtr=nullptr;
    }
    if(m_ybufValuesPtr){
        delete m_ybufValuesPtr;
        m_ybufValuesPtr=nullptr;
    }

    m_xbufValuesPtr = new QVector<double>;
    m_ybufValuesPtr = new QVector<double>;

    if(m_xbufValuesPtr){
        m_xbufValuesPtr->append(xvalues);
    }

    if(m_ybufValuesPtr){
        m_ybufValuesPtr->append(yvalues);
    }

    xvalues.clear();
    yvalues.clear();

    //查找刷新最大 最小值


//    double xmin=0,ymin=0,xmax=0,ymax=0;
    QVector<double>::iterator it;
    if(m_xbufValuesPtr){
        if(m_xbufValuesPtr->count()<1) m_xbufValuesPtr->append(0);
        it = m_xbufValuesPtr->begin();
        m_OrgChxMin=*it;
        m_OrgChxMax=*it;
        for (; it!=m_xbufValuesPtr->end(); it++) {
            if(m_OrgChxMin>*it) m_OrgChxMin=*it;
            if(m_OrgChxMax<*it) m_OrgChxMax=*it;
        }
    }

    if(m_ybufValuesPtr){
        if(m_ybufValuesPtr->count()<1) m_ybufValuesPtr->append(0);
        it = m_ybufValuesPtr->begin();
        m_OrgChyMin=*it;
        m_OrgChyMax=*it;
        for (; it!=m_ybufValuesPtr->end(); it++) {
            if(m_OrgChyMin>*it) m_OrgChyMin=*it;
            if(m_OrgChyMax<*it) m_OrgChyMax=*it;
        }
    }

    m_isLoadingFiles=true;
    ui->spinBox_XMax->setValue(m_OrgChxMax);
    ui->spinBox_XMin->setValue(m_OrgChxMin);
    ui->spinBox_YMax->setValue(m_OrgChyMax);
    ui->spinBox_YMin->setValue(m_OrgChyMin);
    m_isLoadingFiles=false;

    //刷新归一化数据缓冲 和 波形显示窗口
    bufValuesToNormal();

    this->update();
}

///
/// \\brief on_LimitValueChanged
///响应 X Y 通道极限值变化
void MainWidget::on_LimitValueChanged()
{
    if(m_isLoadingFiles) return;
    bufValuesToNormal();

    ui->widget_wave_chX->update();
    ui->widget_wave_chY->update();
}

///
/// \\brief bufValuesToNormal
///原始数据 转换为归一化数据
void MainWidget::bufValuesToNormal()
{
    //    if(m_isLoadingFiles) return;
    m_displayMutex.lock();

    int chx_cnt=0,chy_cnt=0,index0,index1;
    double dt,di,dd;

    m_xNormalValues.clear();
    m_yNormalValues.clear();


    if(m_xbufValuesPtr){
        chx_cnt=m_xbufValuesPtr->count();
    }
    if(m_ybufValuesPtr){
        chy_cnt=m_ybufValuesPtr->count();
    }

    //从原始数据中  抽样  生成每通道 CHANNEL_POINT_CNT 点归一化数据
    for (int i = 0; i < CHANNEL_POINT_CNT; ++i) {
        di=i;
        di=di/(CHANNEL_POINT_CNT-1);

        //Channel x
        if(chx_cnt>0){
            dd=di*(chx_cnt - 1);
            index0=static_cast<int>(dd);
            index1=index0+1;
            dd=dd-index0;
            if(index0>=chx_cnt){
                index0=chx_cnt-1;
                dd=0;
            }
            if(index1>=chx_cnt){
                index1=index0;
                dd=0;
            }

            dt=(*m_xbufValuesPtr)[index0] + dd*((*m_xbufValuesPtr)[index1] - (*m_xbufValuesPtr)[index0]);

            //计算归一化
            if(ui->spinBox_XMax->value() >= ui->spinBox_XMin->value()){
                dt=dt - ui->spinBox_XMin->value();
                dt=dt/(ui->spinBox_XMax->value() - ui->spinBox_XMin->value());
            }else{
                dt=dt - m_OrgChxMin;
                dt=dt/(m_OrgChxMax - m_OrgChxMin);
            }
            if(dt<0) dt=0;
            if(dt>1) dt=1;
            if(std::isnan(dt)) dt=0;
            m_xNormalValues.append(dt);
        }else{
            m_xNormalValues.append(0);
        }

        //Channel y
        if(chy_cnt>0){
            dd=di*(chy_cnt - 1);
            index0=static_cast<int>(dd);
            index1=index0+1;
            dd=dd-index0;
            if(index0>=chy_cnt){
                index0=chy_cnt-1;
                dd=0;
            }
            if(index1>=chy_cnt){
                index1=index0;
                dd=0;
            }

            dt=(*m_ybufValuesPtr)[index0] + dd*((*m_ybufValuesPtr)[index1] - (*m_ybufValuesPtr)[index0]);

            //计算归一化
            if(ui->spinBox_YMax->value() >= ui->spinBox_YMin->value()){
                dt=dt - ui->spinBox_YMin->value();
                dt=dt/(ui->spinBox_YMax->value() - ui->spinBox_YMin->value());
            }else{
                dt=dt - m_OrgChyMin;
                dt=dt/(m_OrgChyMax - m_OrgChyMin);
            }
            if(dt<0) dt=0;
            if(dt>1) dt=1;
            if(std::isnan(dt)) dt=0;
            m_yNormalValues.append(dt);
        }else{
            m_yNormalValues.append(0);
        }
    }

    //    qDebug()<<m_xNormalValues.last();
    //    qDebug()<<m_yNormalValues.last();

    m_displayMutex.unlock();
}


///
/// \\brief paintWaveInWidget 在指定的 widget 中绘制指定颜色的指定数据波形
/// \\param w 目标控件
/// \\param data 绘制的数据
/// \\param color 绘制的波形颜色
///
#define WAVE_WIDGET_BORDER 2
void MainWidget::paintWaveInWidget(QWidget *w, const QVector<double> &data, QColor color)
{
    if(!w) return;

    int width=w->width(),height=w->height();
    int cnt=data.count();

    if(cnt<2) return;

    m_displayMutex.lock();

    QPainter paint(w);
    QPen pen;
    QTransform trans;
    QPointF p1,p2;
    qreal real;

    pen.setColor(color);
    pen.setWidth(2);
    paint.setPen(pen);

    trans.rotate(180,Qt::XAxis);
    trans.translate(0,-height);
    paint.setTransform(trans);

    width=width-WAVE_WIDGET_BORDER*2;
    height=height-WAVE_WIDGET_BORDER*2;
//    paint.drawLine(WAVE_WIDGET_BORDER,WAVE_WIDGET_BORDER,width,height);

    for (int i = 0; i < cnt-1; ++i) {
        real=i;
        p1.setX((width-1)*real/(cnt-1) + WAVE_WIDGET_BORDER);
        real++;
        p2.setX((width-1)*real/(cnt-1) + WAVE_WIDGET_BORDER);

        real=data[i]*(height - 1) + WAVE_WIDGET_BORDER;
        p1.setY(real);
        real=data[i+1]*(height - 1) + WAVE_WIDGET_BORDER;
        p2.setY(real);

        paint.drawLine(p1,p2);
    }

    m_displayMutex.unlock();
}

bool MainWidget::eventFilter(QObject *watched, QEvent *event)
{
    if(event->type()==QEvent::Paint){
        if(watched==ui->widget_wave_chX || watched==ui->widget_wave_chY){
            QPaintEvent *pe = reinterpret_cast<QPaintEvent *>(event);
            if(pe){
                if(watched==ui->widget_wave_chY){
                    paintWaveInWidget(ui->widget_wave_chY,m_yNormalValues,Qt::yellow);
                }else{
                    paintWaveInWidget(ui->widget_wave_chX,m_xNormalValues,Qt::red);
                }
            }
        }
    }

    return false;
}


///
/// \brief on_btnGenHexFile_clicked
/// 响应 生成 Hex文件按钮 按下事件
#define TO_I_SCALE 20000 //转换为单片机整数缩放倍数
void MainWidget::on_btnGenHexFile_clicked()
{
    int xcnt=m_xNormalValues.count();
    int ycnt=m_yNormalValues.count();
    if(xcnt!=CHANNEL_POINT_CNT || ycnt!=CHANNEL_POINT_CNT){
        QMessageBox msgBox;
        msgBox.setText(tr("No vaild data!"));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
        return;
    }

    bool addr_ok=false;
    quint32 s_data=0,s_mcu=0;
    QString startaddr = ui->comboBox_DataAddr->currentText();
    QString mcuentry = ui->comboBox_MCUEntry->currentText();

    s_data=startaddr.toUInt(&addr_ok,16);
    if(!addr_ok){
        QMessageBox msgBox;
        msgBox.setText(tr("Data start address invaild!"));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
        return;
    }

    s_mcu=mcuentry.toUInt(&addr_ok,16);
    if(!addr_ok){
        QMessageBox msgBox;
        msgBox.setText(tr("MCU entry address invaild!"));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
        return;
    }

    QByteArray datebytes;
    double dt;
    qint64 it;
    //X通道转换为 字节流
    for (int i = 0; i < CHANNEL_POINT_CNT; ++i) {
        dt=m_xNormalValues[i]*TO_I_SCALE;
        it=static_cast<qint64>(dt);
        if(it>TO_I_SCALE) it=TO_I_SCALE;
        if(it<0) it=0;
        datebytes.append(
                    *reinterpret_cast<char *>(&it)
                    );
        it=it>>8;
        datebytes.append(
                    *reinterpret_cast<char *>(&it)
                    );
    }

    //Y通道转换为 字节流
    for (int i = 0; i < CHANNEL_POINT_CNT; ++i) {
        dt=m_yNormalValues[i]*TO_I_SCALE;
        it=static_cast<qint64>(dt);
        if(it>TO_I_SCALE) it=TO_I_SCALE;
        if(it<0) it=0;
        datebytes.append(
                    *reinterpret_cast<char *>(&it)
                    );
        it=it>>8;
        datebytes.append(
                    *reinterpret_cast<char *>(&it)
                    );
    }

    //获取保存文件名
    QString savefilename
            = QFileDialog::getSaveFileName(
                nullptr,
                tr("Select Save Hex File Name"),
                nullptr,
                tr("Hex File (*.hex)")
                );

    if(!savefilename.isEmpty()){
        //生成 Hex文件
        bool wrietok=HexFileHelp::writeDataToHexFile(
                    savefilename,
                    s_data,s_mcu,
                    datebytes
                    );

        if(!wrietok){
            QMessageBox msgBox;
            msgBox.setText(tr("Write Data To File '%1' Failed!").arg(savefilename));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.exec();
        }else{
            QMessageBox msgBox;
            msgBox.setText(tr("Generate Hex File Ok!"));
            msgBox.setStandardButtons(QMessageBox::Ok);
            msgBox.exec();
        }
    }
}

///
/// \brief on_btnSendToModbus_clicked
///响应 把数据发送到Modbus按钮 按下事件
void MainWidget::on_btnSendToModbus_clicked()
{
    int xcnt=m_xNormalValues.count();
    int ycnt=m_yNormalValues.count();
    if(xcnt!=CHANNEL_POINT_CNT || ycnt!=CHANNEL_POINT_CNT){
        QMessageBox msgBox;
        msgBox.setText(tr("No vaild data!"));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
        return;
    }

    if(!m_modbusobj) return;

    //获取地址
    quint16 addr=0;
    bool addr_ok=false;
    QString startaddr = ui->comboBox_DstMobusRegAddr->currentText();
    addr=static_cast<quint16>(startaddr.toUInt(&addr_ok,16));
    if(!addr_ok){
        QMessageBox msgBox;
        msgBox.setText(tr("Holding register address invaild!"));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
        return;
    }

    //设置通道参数
    m_modbusobj->setModbusMisc(
                ui->comboboSerialPort->currentText(),
                ui->comboboxBaudrate->currentText().toInt(),
                ui->spinbox_SlaveID->value()
                );
    m_modbusobj->opsIsOK=false;
    m_modbusobj->cancelOps=false;

    //进度对话框
    QProgressDialog dlg;
//    dlg.setWindowTitle(tr("Sending Data..."));
    dlg.setLabelText(tr("Sending Data..."));
    dlg.setAutoClose(true);
    dlg.setWindowFlag(Qt::WindowStaysOnTopHint);
    connect(m_modbusobj,SIGNAL(operatePercent(int)),
            &dlg,SLOT(setValue(int)),
            Qt::QueuedConnection
            );

    //校验失败对话框
    QMessageBox readbackfailedDlg;
    readbackfailedDlg.setText(tr("Readback Data is not equal to writed Or readback failed!"));
    readbackfailedDlg.setStandardButtons(QMessageBox::Ok);
    connect(m_modbusobj,SIGNAL(operateVerifyFailed()),
            &readbackfailedDlg,SLOT(exec()),
            Qt::QueuedConnection
            );

    //拼接数据
    QVector<double> *dt=new QVector<double>(m_xNormalValues);
    dt->append(m_yNormalValues);

    //发送数据
    QMetaObject::invokeMethod(m_modbusobj,
                              "sendDataToHoldRegs",
                              Qt::QueuedConnection,
                              Q_ARG(quint16,addr),
                              Q_ARG(void *,dt),
                              Q_ARG(double,TO_I_SCALE)
                              );

    dlg.exec();

    if(dlg.wasCanceled()){
        m_modbusobj->cancelOps=true;
    }else{
        QMessageBox msgBox;
        if(m_modbusobj->opsIsOK){   //发送成功
            //保存本次操作的参数
            QSettings setting(INI_Cfg_Name,QSettings::IniFormat);
            setting.beginGroup(INI_Cfg_LastVar);
            setting.setValue(INI_Cfg_LastSerialPort,ui->comboboSerialPort->currentText());
            setting.setValue(INI_Cfg_LastBaudrate,ui->comboboxBaudrate->currentText());
            setting.setValue(INI_Cfg_LastSlaveID,ui->spinbox_SlaveID->value());
            setting.endGroup();

            msgBox.setText(tr("Send data by modbus finish!"));
        }else{          //发送失败
            msgBox.setText(tr("Send data by modbus Failed!"));
        }
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
    }

}

///
/// \brief on_btnReadFromModbus_clicked
///响应 从Modbus读取数据按钮 按下事件
void MainWidget::on_btnReadFromModbus_clicked()
{
    if(!m_modbusobj) return;

    //获取地址
    quint16 addr=0;
    bool addr_ok=false;
    QString startaddr = ui->comboBox_DstMobusRegAddr->currentText();
    addr=static_cast<quint16>(startaddr.toUInt(&addr_ok,16));
    if(!addr_ok){
        QMessageBox msgBox;
        msgBox.setText(tr("Holding register address invaild!"));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
        return;
    }

    //选择保存文件名
    QString savefilename;
    savefilename=QFileDialog::getSaveFileName(Q_NULLPTR,
                                     tr("Select Save File"),
                                     nullptr,
                                     tr("CSV File (*.csv)")
                                     );


    if(savefilename.isNull() || savefilename.isEmpty()){
        return;
    }

    //验证文件是否可以打开
    QFile file(savefilename);
    if(file.open(QIODevice::WriteOnly|QIODevice::Text)){
        file.close();
    }else{
        QMessageBox msgBox;
        msgBox.setText(tr("File '%1' can not open!").arg(savefilename));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
        return;
    }

    //设置通道参数
    m_modbusobj->setModbusMisc(
                ui->comboboSerialPort->currentText(),
                ui->comboboxBaudrate->currentText().toInt(),
                ui->spinbox_SlaveID->value()
                );
    m_modbusobj->opsIsOK=false;
    m_modbusobj->cancelOps=false;

    //进度对话框
    QProgressDialog dlg;
//    dlg.setWindowTitle(tr("Reading Data..."));
    dlg.setLabelText(tr("Reading Data..."));
    dlg.setAutoClose(true);
    connect(m_modbusobj,SIGNAL(operatePercent(int)),
            &dlg,SLOT(setValue(int)),
            Qt::QueuedConnection
            );

    //读取数据
    QMetaObject::invokeMethod(m_modbusobj,
                              "readHoldRegsToCSV",
                              Qt::QueuedConnection,
                              Q_ARG(const QString &,savefilename),
                              Q_ARG(quint16,addr),
                              Q_ARG(int,static_cast<quint16>(ui->spinbox_ReadLen->value()))
                              );

    dlg.exec();
    if(dlg.wasCanceled()){
        m_modbusobj->cancelOps=true;
    }else{
        QMessageBox msgBox;
        if(m_modbusobj->opsIsOK){   //发送成功
            //保存本次操作的参数
            QSettings setting(INI_Cfg_Name,QSettings::IniFormat);
            setting.beginGroup(INI_Cfg_LastVar);
            setting.setValue(INI_Cfg_LastSerialPort,ui->comboboSerialPort->currentText());
            setting.setValue(INI_Cfg_LastBaudrate,ui->comboboxBaudrate->currentText());
            setting.setValue(INI_Cfg_LastSlaveID,ui->spinbox_SlaveID->value());
            setting.endGroup();

            msgBox.setText(tr("Read data from modbus finish!"));
        }else{          //发送失败
            msgBox.setText(tr("Read data from modbus Failed!"));
        }
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.exec();
    }
}
